package plp.orientadaObjetos2.comando;

import java.util.ArrayList;
import java.util.HashMap;

import plp.expressions2.memory.VariavelJaDeclaradaException;
import plp.expressions2.memory.VariavelNaoDeclaradaException;
import plp.orientadaObjetos1.declaracao.variavel.DecVariavel;
import plp.orientadaObjetos1.excecao.declaracao.ClasseJaDeclaradaException;
import plp.orientadaObjetos1.excecao.declaracao.ClasseNaoDeclaradaException;
import plp.orientadaObjetos1.excecao.declaracao.ObjetoJaDeclaradoException;
import plp.orientadaObjetos1.excecao.declaracao.ObjetoNaoDeclaradoException;
import plp.orientadaObjetos1.excecao.declaracao.ProcedimentoJaDeclaradoException;
import plp.orientadaObjetos1.excecao.declaracao.ProcedimentoNaoDeclaradoException;
import plp.orientadaObjetos1.excecao.execucao.EntradaInvalidaException;
import plp.orientadaObjetos1.expressao.Expressao;
import plp.orientadaObjetos1.expressao.ListaExpressao;
import plp.orientadaObjetos1.expressao.leftExpression.Id;
import plp.orientadaObjetos1.expressao.valor.Valor;
import plp.orientadaObjetos1.expressao.valor.ValorBooleano;
import plp.orientadaObjetos1.expressao.valor.ValorInteiro;
import plp.orientadaObjetos1.expressao.valor.ValorRef;
import plp.orientadaObjetos1.memoria.AmbienteExecucaoOO1;
import plp.orientadaObjetos1.memoria.ContextoExecucaoOO1;
import plp.orientadaObjetos1.memoria.Objeto;
import plp.orientadaObjetos1.util.Tipo;
import plp.orientadaObjetos2.memoria.AmbienteExecucaoOO2;
import plp.orientadaObjetos2.memoria.DefClasseOO2;
import plp.orientadaObjetos2.reflection.ReflectionUtil;

public class InstanceHandler extends AbstractComandoHandler {
	
	@Override
	public boolean aceita(Expressao comando){
		boolean retorno = false;
		if (comando.toString().equals("instance"))
			retorno = true;
		
		return retorno;
	}
	
	@Override
	public void manipula(ComandoBean comandoBean) throws ClasseNaoDeclaradaException,
		VariavelNaoDeclaradaException, VariavelJaDeclaradaException, ObjetoNaoDeclaradoException, ClasseJaDeclaradaException, ObjetoJaDeclaradoException, 
		ProcedimentoNaoDeclaradoException, ProcedimentoJaDeclaradoException, EntradaInvalidaException{
		
		Id nomeClasse = new Id("nome_classe");
    	Id av = comandoBean.getAvx().getId();
    	Id classe = new Id(comandoBean.getObjeto().getEstado().get(nomeClasse).toString());
    	
    	
    	//TO DO: Implementar a validacao para passar o params vazio ou nao
    	//ListaExpressao parametrosReaisx = params;
		ListaExpressao parametrosReaisx = new ListaExpressao();
    	
    	NewOO2 obj;
    	if (ReflectionUtil.isMetaClasse(classe)){
    		obj = new NewOO2Reflection(av, classe, parametrosReaisx);
    	} else{
    		obj = new NewOO2Padrao(av, classe, parametrosReaisx);
    	}
    	
    	obj.executar((AmbienteExecucaoOO2)comandoBean.getAmbiente());
    	Id oId = new Id("o");
    	ValorRef oVr = (ValorRef) av.avaliar(comandoBean.getAmbiente());
    	//ambiente = new Atribuicao(oId,oVr).executar(ambiente);
    	comandoBean.getObjeto().changeAtributo(oId, oVr);
		
	}

	
	protected void criaEstadoDoObjetoNasSuperClasses(AmbienteExecucaoOO2 ambiente, DefClasseOO2 classe, Objeto objeto) throws ClasseNaoDeclaradaException, 
	VariavelNaoDeclaradaException, VariavelJaDeclaradaException, ObjetoNaoDeclaradoException, 
	ClasseJaDeclaradaException, ObjetoJaDeclaradoException {
		if (classe.getNomeSuperClasse() != null) {
		DefClasseOO2 classeMae = (DefClasseOO2) ambiente.getDefClasse(classe.getNomeSuperClasse());
		this.criaEstadoDoObjetoNasSuperClasses(ambiente, classeMae,objeto);
		}
		
		DecVariavel decVariavel = classe.getDecVariavel();
		AmbienteExecucaoOO1 aux = decVariavel.elabora(new ContextoExecucaoOO1(ambiente));
		HashMap<plp.expressions2.expression.Id, Valor> estadoObj = aux.getPilha().pop();
		
		for (plp.expressions2.expression.Id id : estadoObj.keySet()) {
		// Se a variavel nao havia sido declarada adicione
		if (!objeto.getEstado().containsKey(id) ) {
			objeto.getEstado().put(id, estadoObj.get(id));	
		}
	}
}


}


